home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 13 The Compute Shader / WavesCS / WavesCSApp.cpp < prev   
Encoding:
C/C++ Source or Header  |  2016-03-02  |  42.6 KB  |  1,189 lines

  1. //***************************************************************************************
  2. // WavesCSApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "FrameResource.h"
  10. #include "GpuWaves.h"
  11.  
  12. using Microsoft::WRL::ComPtr;
  13. using namespace DirectX;
  14. using namespace DirectX::PackedVector;
  15.  
  16. #pragma comment(lib, "d3dcompiler.lib")
  17. #pragma comment(lib, "D3D12.lib")
  18.  
  19. const int gNumFrameResources = 3;
  20.  
  21. // Lightweight structure stores parameters to draw a shape.  This will
  22. // vary from app-to-app.
  23. struct RenderItem
  24. {
  25.     RenderItem() = default;
  26.  
  27.     // World matrix of the shape that describes the object's local space
  28.     // relative to the world space, which defines the position, orientation,
  29.     // and scale of the object in the world.
  30.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  31.  
  32.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  33.  
  34.     // Used for GPU waves render items.
  35.     DirectX::XMFLOAT2 DisplacementMapTexelSize = { 1.0f, 1.0f };
  36.     float GridSpatialStep = 1.0f;
  37.  
  38.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  39.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  40.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  41.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  42.     int NumFramesDirty = gNumFrameResources;
  43.  
  44.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  45.     UINT ObjCBIndex = -1;
  46.  
  47.     Material* Mat = nullptr;
  48.     MeshGeometry* Geo = nullptr;
  49.  
  50.     // Primitive topology.
  51.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  52.  
  53.     // DrawIndexedInstanced parameters.
  54.     UINT IndexCount = 0;
  55.     UINT StartIndexLocation = 0;
  56.     int BaseVertexLocation = 0;
  57. };
  58.  
  59. enum class RenderLayer : int
  60. {
  61.     Opaque = 0,
  62.     Transparent,
  63.     AlphaTested,
  64.     GpuWaves,
  65.     Count
  66. };
  67.  
  68. class WavesCSApp : public D3DApp
  69. {
  70. public:
  71.     WavesCSApp(HINSTANCE hInstance);
  72.     WavesCSApp(const WavesCSApp& rhs) = delete;
  73.     WavesCSApp& operator=(const WavesCSApp& rhs) = delete;
  74.     ~WavesCSApp();
  75.  
  76.     virtual bool Initialize()override;
  77.  
  78. private:
  79.     virtual void OnResize()override;
  80.     virtual void Update(const GameTimer& gt)override;
  81.     virtual void Draw(const GameTimer& gt)override;
  82.  
  83.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  84.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  85.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  86.  
  87.     void OnKeyboardInput(const GameTimer& gt);
  88.     void UpdateCamera(const GameTimer& gt);
  89.     void AnimateMaterials(const GameTimer& gt);
  90.     void UpdateObjectCBs(const GameTimer& gt);
  91.     void UpdateMaterialCBs(const GameTimer& gt);
  92.     void UpdateMainPassCB(const GameTimer& gt);
  93.     void UpdateWavesGPU(const GameTimer& gt);
  94.  
  95.     void LoadTextures();
  96.     void BuildRootSignature();
  97.     void BuildWavesRootSignature();
  98.     void BuildDescriptorHeaps();
  99.     void BuildShadersAndInputLayout();
  100.     void BuildLandGeometry();
  101.     void BuildWavesGeometry();
  102.     void BuildBoxGeometry();
  103.     void BuildPSOs();
  104.     void BuildFrameResources();
  105.     void BuildMaterials();
  106.     void BuildRenderItems();
  107.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  108.  
  109.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  110.  
  111.     float GetHillsHeight(float x, float z)const;
  112.     XMFLOAT3 GetHillsNormal(float x, float z)const;
  113.  
  114. private:
  115.  
  116.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  117.     FrameResource* mCurrFrameResource = nullptr;
  118.     int mCurrFrameResourceIndex = 0;
  119.  
  120.     UINT mCbvSrvDescriptorSize = 0;
  121.  
  122.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  123.     ComPtr<ID3D12RootSignature> mWavesRootSignature = nullptr;
  124.  
  125.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  126.  
  127.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  128.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  129.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  130.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  131.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  132.  
  133.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  134.  
  135.     // List of all the render items.
  136.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  137.  
  138.     // Render items divided by PSO.
  139.     std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
  140.  
  141.     std::unique_ptr<GpuWaves> mWaves;
  142.  
  143.     PassConstants mMainPassCB;
  144.  
  145.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  146.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  147.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  148.  
  149.     float mTheta = 1.5f*XM_PI;
  150.     float mPhi = XM_PIDIV2 - 0.1f;
  151.     float mRadius = 50.0f;
  152.  
  153.     POINT mLastMousePos;
  154. };
  155.  
  156. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  157.     PSTR cmdLine, int showCmd)
  158. {
  159.     // Enable run-time memory check for debug builds.
  160. #if defined(DEBUG) | defined(_DEBUG)
  161.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  162. #endif
  163.  
  164.     try
  165.     {
  166.         WavesCSApp theApp(hInstance);
  167.         if(!theApp.Initialize())
  168.             return 0;
  169.  
  170.         return theApp.Run();
  171.     }
  172.     catch(DxException& e)
  173.     {
  174.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  175.         return 0;
  176.     }
  177. }
  178.  
  179. WavesCSApp::WavesCSApp(HINSTANCE hInstance)
  180.     : D3DApp(hInstance)
  181. {
  182. }
  183.  
  184. WavesCSApp::~WavesCSApp()
  185. {
  186.     if(md3dDevice != nullptr)
  187.         FlushCommandQueue();
  188. }
  189.  
  190. bool WavesCSApp::Initialize()
  191. {
  192.     if(!D3DApp::Initialize())
  193.         return false;
  194.  
  195.     // Reset the command list to prep for initialization commands.
  196.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  197.  
  198.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  199.     // so we have to query this information.
  200.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  201.  
  202.     mWaves = std::make_unique<GpuWaves>(
  203.         md3dDevice.Get(), 
  204.         mCommandList.Get(),
  205.         256, 256, 0.25f, 0.03f, 2.0f, 0.2f);
  206.  
  207.     LoadTextures();
  208.     BuildRootSignature();
  209.     BuildWavesRootSignature();
  210.     BuildDescriptorHeaps();
  211.     BuildShadersAndInputLayout();
  212.     BuildLandGeometry();
  213.     BuildWavesGeometry();
  214.     BuildBoxGeometry();
  215.     BuildMaterials();
  216.     BuildRenderItems();
  217.     BuildFrameResources();
  218.     BuildPSOs();
  219.  
  220.     // Execute the initialization commands.
  221.     ThrowIfFailed(mCommandList->Close());
  222.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  223.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  224.  
  225.     // Wait until initialization is complete.
  226.     FlushCommandQueue();
  227.  
  228.     return true;
  229. }
  230.  
  231. void WavesCSApp::OnResize()
  232. {
  233.     D3DApp::OnResize();
  234.  
  235.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  236.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  237.     XMStoreFloat4x4(&mProj, P);
  238. }
  239.  
  240. void WavesCSApp::Update(const GameTimer& gt)
  241. {
  242.     OnKeyboardInput(gt);
  243.     UpdateCamera(gt);
  244.  
  245.     // Cycle through the circular frame resource array.
  246.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  247.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  248.  
  249.     // Has the GPU finished processing the commands of the current frame resource?
  250.     // If not, wait until the GPU has completed commands up to this fence point.
  251.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  252.     {
  253.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  254.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  255.         WaitForSingleObject(eventHandle, INFINITE);
  256.         CloseHandle(eventHandle);
  257.     }
  258.  
  259.     AnimateMaterials(gt);
  260.     UpdateObjectCBs(gt);
  261.     UpdateMaterialCBs(gt);
  262.     UpdateMainPassCB(gt);
  263. }
  264.  
  265. void WavesCSApp::Draw(const GameTimer& gt)
  266. {
  267.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  268.  
  269.     // Reuse the memory associated with command recording.
  270.     // We can only reset when the associated command lists have finished execution on the GPU.
  271.     ThrowIfFailed(cmdListAlloc->Reset());
  272.  
  273.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  274.     // Reusing the command list reuses memory.
  275.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  276.  
  277.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  278.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  279.  
  280.     UpdateWavesGPU(gt);
  281.  
  282.     mCommandList->SetPipelineState(mPSOs["opaque"].Get());
  283.  
  284.     mCommandList->RSSetViewports(1, &mScreenViewport);
  285.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  286.  
  287.     // Indicate a state transition on the resource usage.
  288.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  289.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  290.  
  291.     // Clear the back buffer and depth buffer.
  292.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), (float*)&mMainPassCB.FogColor, 0, nullptr);
  293.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  294.  
  295.     // Specify the buffers we are going to render to.
  296.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  297.  
  298.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  299.  
  300.     auto passCB = mCurrFrameResource->PassCB->Resource();
  301.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  302.  
  303.     mCommandList->SetGraphicsRootDescriptorTable(4, mWaves->DisplacementMap());
  304.  
  305.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
  306.  
  307.     mCommandList->SetPipelineState(mPSOs["alphaTested"].Get());
  308.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::AlphaTested]);
  309.  
  310.     mCommandList->SetPipelineState(mPSOs["transparent"].Get());
  311.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Transparent]);
  312.  
  313.     mCommandList->SetPipelineState(mPSOs["wavesRender"].Get());
  314.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::GpuWaves]);
  315.  
  316.     // Indicate a state transition on the resource usage.
  317.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  318.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  319.  
  320.     // Done recording commands.
  321.     ThrowIfFailed(mCommandList->Close());
  322.  
  323.     // Add the command list to the queue for execution.
  324.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  325.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  326.  
  327.     // Swap the back and front buffers
  328.     ThrowIfFailed(mSwapChain->Present(0, 0));
  329.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  330.  
  331.     // Advance the fence value to mark commands up to this fence point.
  332.     mCurrFrameResource->Fence = ++mCurrentFence;
  333.  
  334.     // Add an instruction to the command queue to set a new fence point. 
  335.     // Because we are on the GPU timeline, the new fence point won't be 
  336.     // set until the GPU finishes processing all the commands prior to this Signal().
  337.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  338. }
  339.  
  340. void WavesCSApp::OnMouseDown(WPARAM btnState, int x, int y)
  341. {
  342.     mLastMousePos.x = x;
  343.     mLastMousePos.y = y;
  344.  
  345.     SetCapture(mhMainWnd);
  346. }
  347.  
  348. void WavesCSApp::OnMouseUp(WPARAM btnState, int x, int y)
  349. {
  350.     ReleaseCapture();
  351. }
  352.  
  353. void WavesCSApp::OnMouseMove(WPARAM btnState, int x, int y)
  354. {
  355.     if((btnState & MK_LBUTTON) != 0)
  356.     {
  357.         // Make each pixel correspond to a quarter of a degree.
  358.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  359.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  360.  
  361.         // Update angles based on input to orbit camera around box.
  362.         mTheta += dx;
  363.         mPhi += dy;
  364.  
  365.         // Restrict the angle mPhi.
  366.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  367.     }
  368.     else if((btnState & MK_RBUTTON) != 0)
  369.     {
  370.         // Make each pixel correspond to 0.2 unit in the scene.
  371.         float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
  372.         float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
  373.  
  374.         // Update the camera radius based on input.
  375.         mRadius += dx - dy;
  376.  
  377.         // Restrict the radius.
  378.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  379.     }
  380.  
  381.     mLastMousePos.x = x;
  382.     mLastMousePos.y = y;
  383. }
  384.  
  385. void WavesCSApp::OnKeyboardInput(const GameTimer& gt)
  386. {
  387. }
  388.  
  389. void WavesCSApp::UpdateCamera(const GameTimer& gt)
  390. {
  391.     // Convert Spherical to Cartesian coordinates.
  392.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  393.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  394.     mEyePos.y = mRadius*cosf(mPhi);
  395.  
  396.     // Build the view matrix.
  397.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  398.     XMVECTOR target = XMVectorZero();
  399.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  400.  
  401.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  402.     XMStoreFloat4x4(&mView, view);
  403. }
  404.  
  405. void WavesCSApp::AnimateMaterials(const GameTimer& gt)
  406. {
  407.     // Scroll the water material texture coordinates.
  408.     auto waterMat = mMaterials["water"].get();
  409.  
  410.     float& tu = waterMat->MatTransform(3, 0);
  411.     float& tv = waterMat->MatTransform(3, 1);
  412.  
  413.     tu += 0.1f * gt.DeltaTime();
  414.     tv += 0.02f * gt.DeltaTime();
  415.  
  416.     if(tu >= 1.0f)
  417.         tu -= 1.0f;
  418.  
  419.     if(tv >= 1.0f)
  420.         tv -= 1.0f;
  421.  
  422.     waterMat->MatTransform(3, 0) = tu;
  423.     waterMat->MatTransform(3, 1) = tv;
  424.  
  425.     // Material has changed, so need to update cbuffer.
  426.     waterMat->NumFramesDirty = gNumFrameResources;
  427. }
  428.  
  429. void WavesCSApp::UpdateObjectCBs(const GameTimer& gt)
  430. {
  431.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  432.     for(auto& e : mAllRitems)
  433.     {
  434.         // Only update the cbuffer data if the constants have changed.  
  435.         // This needs to be tracked per frame resource.
  436.         if(e->NumFramesDirty > 0)
  437.         {
  438.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  439.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  440.  
  441.             ObjectConstants objConstants;
  442.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  443.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  444.             objConstants.DisplacementMapTexelSize = e->DisplacementMapTexelSize;
  445.             objConstants.GridSpatialStep = e->GridSpatialStep;
  446.  
  447.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  448.  
  449.             // Next FrameResource need to be updated too.
  450.             e->NumFramesDirty--;
  451.         }
  452.     }
  453. }
  454.  
  455. void WavesCSApp::UpdateMaterialCBs(const GameTimer& gt)
  456. {
  457.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  458.     for(auto& e : mMaterials)
  459.     {
  460.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  461.         // data changes, it needs to be updated for each FrameResource.
  462.         Material* mat = e.second.get();
  463.         if(mat->NumFramesDirty > 0)
  464.         {
  465.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  466.  
  467.             MaterialConstants matConstants;
  468.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  469.             matConstants.FresnelR0 = mat->FresnelR0;
  470.             matConstants.Roughness = mat->Roughness;
  471.             XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
  472.  
  473.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  474.  
  475.             // Next FrameResource need to be updated too.
  476.             mat->NumFramesDirty--;
  477.         }
  478.     }
  479. }
  480.  
  481. void WavesCSApp::UpdateMainPassCB(const GameTimer& gt)
  482. {
  483.     XMMATRIX view = XMLoadFloat4x4(&mView);
  484.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  485.  
  486.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  487.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  488.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  489.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  490.  
  491.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  492.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  493.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  494.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  495.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  496.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  497.     mMainPassCB.EyePosW = mEyePos;
  498.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  499.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  500.     mMainPassCB.NearZ = 1.0f;
  501.     mMainPassCB.FarZ = 1000.0f;
  502.     mMainPassCB.TotalTime = gt.TotalTime();
  503.     mMainPassCB.DeltaTime = gt.DeltaTime();
  504.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  505.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  506.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  507.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  508.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  509.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  510.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  511.  
  512.     auto currPassCB = mCurrFrameResource->PassCB.get();
  513.     currPassCB->CopyData(0, mMainPassCB);
  514. }
  515.  
  516. void WavesCSApp::UpdateWavesGPU(const GameTimer& gt)
  517. {
  518.     // Every quarter second, generate a random wave.
  519.     static float t_base = 0.0f;
  520.     if((mTimer.TotalTime() - t_base) >= 0.25f)
  521.     {
  522.         t_base += 0.25f;
  523.  
  524.         int i = MathHelper::Rand(4, mWaves->RowCount() - 5);
  525.         int j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
  526.  
  527.         float r = MathHelper::RandF(1.0f, 2.0f);
  528.  
  529.         mWaves->Disturb(mCommandList.Get(), mWavesRootSignature.Get(), mPSOs["wavesDisturb"].Get(), i, j, r);
  530.     }
  531.  
  532.     // Update the wave simulation.
  533.     mWaves->Update(gt, mCommandList.Get(), mWavesRootSignature.Get(), mPSOs["wavesUpdate"].Get());
  534. }
  535.  
  536. void WavesCSApp::LoadTextures()
  537. {
  538.     auto grassTex = std::make_unique<Texture>();
  539.     grassTex->Name = "grassTex";
  540.     grassTex->Filename = L"../../Textures/grass.dds";
  541.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  542.         mCommandList.Get(), grassTex->Filename.c_str(),
  543.         grassTex->Resource, grassTex->UploadHeap));
  544.  
  545.     auto waterTex = std::make_unique<Texture>();
  546.     waterTex->Name = "waterTex";
  547.     waterTex->Filename = L"../../Textures/water1.dds";
  548.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  549.         mCommandList.Get(), waterTex->Filename.c_str(),
  550.         waterTex->Resource, waterTex->UploadHeap));
  551.  
  552.     auto fenceTex = std::make_unique<Texture>();
  553.     fenceTex->Name = "fenceTex";
  554.     fenceTex->Filename = L"../../Textures/WireFence.dds";
  555.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  556.         mCommandList.Get(), fenceTex->Filename.c_str(),
  557.         fenceTex->Resource, fenceTex->UploadHeap));
  558.  
  559.     mTextures[grassTex->Name] = std::move(grassTex);
  560.     mTextures[waterTex->Name] = std::move(waterTex);
  561.     mTextures[fenceTex->Name] = std::move(fenceTex);
  562. }
  563.  
  564. void WavesCSApp::BuildRootSignature()
  565. {
  566.     CD3DX12_DESCRIPTOR_RANGE texTable;
  567.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  568.  
  569.     CD3DX12_DESCRIPTOR_RANGE displacementMapTable;
  570.     displacementMapTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);
  571.  
  572.     // Root parameter can be a table, root descriptor or root constants.
  573.     CD3DX12_ROOT_PARAMETER slotRootParameter[5];
  574.  
  575.     // Perfomance TIP: Order from most frequent to least frequent.
  576.     slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_ALL);
  577.     slotRootParameter[1].InitAsConstantBufferView(0);
  578.     slotRootParameter[2].InitAsConstantBufferView(1);
  579.     slotRootParameter[3].InitAsConstantBufferView(2);
  580.     slotRootParameter[4].InitAsDescriptorTable(1, &displacementMapTable, D3D12_SHADER_VISIBILITY_ALL);
  581.  
  582.     auto staticSamplers = GetStaticSamplers();
  583.  
  584.     // A root signature is an array of root parameters.
  585.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(5, slotRootParameter,
  586.         (UINT)staticSamplers.size(), staticSamplers.data(),
  587.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  588.  
  589.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  590.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  591.     ComPtr<ID3DBlob> errorBlob = nullptr;
  592.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  593.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  594.  
  595.     if(errorBlob != nullptr)
  596.     {
  597.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  598.     }
  599.     ThrowIfFailed(hr);
  600.  
  601.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  602.         0,
  603.         serializedRootSig->GetBufferPointer(),
  604.         serializedRootSig->GetBufferSize(),
  605.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  606. }
  607.  
  608. void WavesCSApp::BuildWavesRootSignature()
  609. {
  610.     CD3DX12_DESCRIPTOR_RANGE uavTable0;
  611.     uavTable0.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0);
  612.  
  613.     CD3DX12_DESCRIPTOR_RANGE uavTable1;
  614.     uavTable1.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 1);
  615.  
  616.     CD3DX12_DESCRIPTOR_RANGE uavTable2;
  617.     uavTable2.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 2);
  618.  
  619.     // Root parameter can be a table, root descriptor or root constants.
  620.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  621.  
  622.     // Perfomance TIP: Order from most frequent to least frequent.
  623.     slotRootParameter[0].InitAsConstants(6, 0);
  624.     slotRootParameter[1].InitAsDescriptorTable(1, &uavTable0);
  625.     slotRootParameter[2].InitAsDescriptorTable(1, &uavTable1);
  626.     slotRootParameter[3].InitAsDescriptorTable(1, &uavTable2);
  627.  
  628.     // A root signature is an array of root parameters.
  629.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  630.         0, nullptr,
  631.         D3D12_ROOT_SIGNATURE_FLAG_NONE);
  632.  
  633.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  634.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  635.     ComPtr<ID3DBlob> errorBlob = nullptr;
  636.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  637.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  638.  
  639.     if(errorBlob != nullptr)
  640.     {
  641.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  642.     }
  643.     ThrowIfFailed(hr);
  644.  
  645.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  646.         0,
  647.         serializedRootSig->GetBufferPointer(),
  648.         serializedRootSig->GetBufferSize(),
  649.         IID_PPV_ARGS(mWavesRootSignature.GetAddressOf())));
  650. }
  651.  
  652. void WavesCSApp::BuildDescriptorHeaps()
  653. {
  654.     UINT srvCount = 3;
  655.  
  656.     //
  657.     // Create the SRV heap.
  658.     //
  659.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  660.     srvHeapDesc.NumDescriptors = srvCount + mWaves->DescriptorCount();
  661.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  662.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  663.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  664.  
  665.     //
  666.     // Fill out the heap with actual descriptors.  
  667.     //
  668.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  669.  
  670.     auto grassTex = mTextures["grassTex"]->Resource;
  671.     auto waterTex = mTextures["waterTex"]->Resource;
  672.     auto fenceTex = mTextures["fenceTex"]->Resource;
  673.  
  674.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  675.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  676.     srvDesc.Format = grassTex->GetDesc().Format;
  677.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  678.     srvDesc.Texture2D.MostDetailedMip = 0;
  679.     srvDesc.Texture2D.MipLevels = -1;
  680.     md3dDevice->CreateShaderResourceView(grassTex.Get(), &srvDesc, hDescriptor);
  681.  
  682.     // next descriptor
  683.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  684.  
  685.     srvDesc.Format = waterTex->GetDesc().Format;
  686.     md3dDevice->CreateShaderResourceView(waterTex.Get(), &srvDesc, hDescriptor);
  687.  
  688.     // next descriptor
  689.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  690.  
  691.     srvDesc.Format = fenceTex->GetDesc().Format;
  692.     md3dDevice->CreateShaderResourceView(fenceTex.Get(), &srvDesc, hDescriptor);
  693.  
  694.     mWaves->BuildDescriptors(
  695.         CD3DX12_CPU_DESCRIPTOR_HANDLE(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), srvCount, mCbvSrvDescriptorSize),
  696.         CD3DX12_GPU_DESCRIPTOR_HANDLE(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart(), srvCount, mCbvSrvDescriptorSize),
  697.         mCbvSrvDescriptorSize);
  698. }
  699.  
  700. void WavesCSApp::BuildShadersAndInputLayout()
  701. {
  702.     const D3D_SHADER_MACRO defines[] =
  703.     {
  704.         "FOG", "1",
  705.         NULL, NULL
  706.     };
  707.  
  708.     const D3D_SHADER_MACRO alphaTestDefines[] =
  709.     {
  710.         "FOG", "1",
  711.         "ALPHA_TEST", "1",
  712.         NULL, NULL
  713.     };
  714.  
  715.     const D3D_SHADER_MACRO waveDefines[] =
  716.     {
  717.         "DISPLACEMENT_MAP", "1",
  718.         NULL, NULL
  719.     };
  720.  
  721.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
  722.     mShaders["wavesVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", waveDefines, "VS", "vs_5_0");
  723.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", defines, "PS", "ps_5_0");
  724.     mShaders["alphaTestedPS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", alphaTestDefines, "PS", "ps_5_0");
  725.     mShaders["wavesUpdateCS"] = d3dUtil::CompileShader(L"Shaders\\WaveSim.hlsl", nullptr, "UpdateWavesCS", "cs_5_0");
  726.     mShaders["wavesDisturbCS"] = d3dUtil::CompileShader(L"Shaders\\WaveSim.hlsl", nullptr, "DisturbWavesCS", "cs_5_0");
  727.  
  728.     mInputLayout =
  729.     {
  730.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  731.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  732.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  733.     };
  734. }
  735.  
  736. void WavesCSApp::BuildLandGeometry()
  737. {
  738.     GeometryGenerator geoGen;
  739.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
  740.  
  741.     //
  742.     // Extract the vertex elements we are interested and apply the height function to
  743.     // each vertex.  In addition, color the vertices based on their height so we have
  744.     // sandy looking beaches, grassy low hills, and snow mountain peaks.
  745.     //
  746.  
  747.     std::vector<Vertex> vertices(grid.Vertices.size());
  748.     for(size_t i = 0; i < grid.Vertices.size(); ++i)
  749.     {
  750.         auto& p = grid.Vertices[i].Position;
  751.         vertices[i].Pos = p;
  752.         vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
  753.         vertices[i].Normal = GetHillsNormal(p.x, p.z);
  754.         vertices[i].TexC = grid.Vertices[i].TexC;
  755.     }
  756.  
  757.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  758.  
  759.     std::vector<std::uint16_t> indices = grid.GetIndices16();
  760.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  761.  
  762.     auto geo = std::make_unique<MeshGeometry>();
  763.     geo->Name = "landGeo";
  764.  
  765.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  766.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  767.  
  768.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  769.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  770.  
  771.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  772.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  773.  
  774.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  775.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  776.  
  777.     geo->VertexByteStride = sizeof(Vertex);
  778.     geo->VertexBufferByteSize = vbByteSize;
  779.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  780.     geo->IndexBufferByteSize = ibByteSize;
  781.  
  782.     SubmeshGeometry submesh;
  783.     submesh.IndexCount = (UINT)indices.size();
  784.     submesh.StartIndexLocation = 0;
  785.     submesh.BaseVertexLocation = 0;
  786.  
  787.     geo->DrawArgs["grid"] = submesh;
  788.  
  789.     mGeometries["landGeo"] = std::move(geo);
  790. }
  791.  
  792. void WavesCSApp::BuildWavesGeometry()
  793. {
  794.     GeometryGenerator geoGen;
  795.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, mWaves->RowCount(), mWaves->ColumnCount());
  796.  
  797.     std::vector<Vertex> vertices(grid.Vertices.size());
  798.     for(size_t i = 0; i < grid.Vertices.size(); ++i)
  799.     {
  800.         vertices[i].Pos = grid.Vertices[i].Position;
  801.         vertices[i].Normal = grid.Vertices[i].Normal;
  802.         vertices[i].TexC = grid.Vertices[i].TexC;
  803.     }
  804.  
  805.     std::vector<std::uint32_t> indices = grid.Indices32;
  806.  
  807.     UINT vbByteSize = mWaves->VertexCount()*sizeof(Vertex);
  808.     UINT ibByteSize = (UINT)indices.size()*sizeof(std::uint32_t);
  809.  
  810.     auto geo = std::make_unique<MeshGeometry>();
  811.     geo->Name = "waterGeo";
  812.  
  813.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  814.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  815.  
  816.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  817.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  818.  
  819.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  820.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  821.  
  822.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  823.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  824.  
  825.     geo->VertexByteStride = sizeof(Vertex);
  826.     geo->VertexBufferByteSize = vbByteSize;
  827.     geo->IndexFormat = DXGI_FORMAT_R32_UINT;
  828.     geo->IndexBufferByteSize = ibByteSize;
  829.  
  830.     SubmeshGeometry submesh;
  831.     submesh.IndexCount = (UINT)indices.size();
  832.     submesh.StartIndexLocation = 0;
  833.     submesh.BaseVertexLocation = 0;
  834.  
  835.     geo->DrawArgs["grid"] = submesh;
  836.  
  837.     mGeometries["waterGeo"] = std::move(geo);
  838. }
  839.  
  840. void WavesCSApp::BuildBoxGeometry()
  841. {
  842.     GeometryGenerator geoGen;
  843.     GeometryGenerator::MeshData box = geoGen.CreateBox(8.0f, 8.0f, 8.0f, 3);
  844.  
  845.     std::vector<Vertex> vertices(box.Vertices.size());
  846.     for (size_t i = 0; i < box.Vertices.size(); ++i)
  847.     {
  848.         auto& p = box.Vertices[i].Position;
  849.         vertices[i].Pos = p;
  850.         vertices[i].Normal = box.Vertices[i].Normal;
  851.         vertices[i].TexC = box.Vertices[i].TexC;
  852.     }
  853.  
  854.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  855.  
  856.     std::vector<std::uint16_t> indices = box.GetIndices16();
  857.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  858.  
  859.     auto geo = std::make_unique<MeshGeometry>();
  860.     geo->Name = "boxGeo";
  861.  
  862.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  863.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  864.  
  865.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  866.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  867.  
  868.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  869.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  870.  
  871.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  872.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  873.  
  874.     geo->VertexByteStride = sizeof(Vertex);
  875.     geo->VertexBufferByteSize = vbByteSize;
  876.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  877.     geo->IndexBufferByteSize = ibByteSize;
  878.  
  879.     SubmeshGeometry submesh;
  880.     submesh.IndexCount = (UINT)indices.size();
  881.     submesh.StartIndexLocation = 0;
  882.     submesh.BaseVertexLocation = 0;
  883.  
  884.     geo->DrawArgs["box"] = submesh;
  885.  
  886.     mGeometries["boxGeo"] = std::move(geo);
  887. }
  888.  
  889. void WavesCSApp::BuildPSOs()
  890. {
  891.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  892.  
  893.     //
  894.     // PSO for opaque objects.
  895.     //
  896.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  897.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  898.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  899.     opaquePsoDesc.VS = 
  900.     { 
  901.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  902.         mShaders["standardVS"]->GetBufferSize()
  903.     };
  904.     opaquePsoDesc.PS = 
  905.     { 
  906.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  907.         mShaders["opaquePS"]->GetBufferSize()
  908.     };
  909.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  910.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  911.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  912.     opaquePsoDesc.SampleMask = UINT_MAX;
  913.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  914.     opaquePsoDesc.NumRenderTargets = 1;
  915.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  916.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  917.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  918.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  919.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  920.  
  921.     //
  922.     // PSO for transparent objects
  923.     //
  924.  
  925.     D3D12_GRAPHICS_PIPELINE_STATE_DESC transparentPsoDesc = opaquePsoDesc;
  926.  
  927.     D3D12_RENDER_TARGET_BLEND_DESC transparencyBlendDesc;
  928.     transparencyBlendDesc.BlendEnable = true;
  929.     transparencyBlendDesc.LogicOpEnable = false;
  930.     transparencyBlendDesc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  931.     transparencyBlendDesc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  932.     transparencyBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
  933.     transparencyBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
  934.     transparencyBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
  935.     transparencyBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  936.     transparencyBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
  937.     transparencyBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  938.  
  939.     transparentPsoDesc.BlendState.RenderTarget[0] = transparencyBlendDesc;
  940.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&transparentPsoDesc, IID_PPV_ARGS(&mPSOs["transparent"])));
  941.  
  942.     //
  943.     // PSO for alpha tested objects
  944.     //
  945.  
  946.     D3D12_GRAPHICS_PIPELINE_STATE_DESC alphaTestedPsoDesc = opaquePsoDesc;
  947.     alphaTestedPsoDesc.PS = 
  948.     { 
  949.         reinterpret_cast<BYTE*>(mShaders["alphaTestedPS"]->GetBufferPointer()),
  950.         mShaders["alphaTestedPS"]->GetBufferSize()
  951.     };
  952.     alphaTestedPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  953.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&alphaTestedPsoDesc, IID_PPV_ARGS(&mPSOs["alphaTested"])));
  954.  
  955.     //
  956.     // PSO for drawing waves
  957.     //
  958.     D3D12_GRAPHICS_PIPELINE_STATE_DESC wavesRenderPSO = transparentPsoDesc;
  959.     wavesRenderPSO.VS =
  960.     {
  961.         reinterpret_cast<BYTE*>(mShaders["wavesVS"]->GetBufferPointer()),
  962.         mShaders["wavesVS"]->GetBufferSize()
  963.     };
  964.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&wavesRenderPSO, IID_PPV_ARGS(&mPSOs["wavesRender"])));
  965.  
  966.     //
  967.     // PSO for disturbing waves
  968.     //
  969.     D3D12_COMPUTE_PIPELINE_STATE_DESC wavesDisturbPSO = {};
  970.     wavesDisturbPSO.pRootSignature = mWavesRootSignature.Get();
  971.     wavesDisturbPSO.CS =
  972.     {
  973.         reinterpret_cast<BYTE*>(mShaders["wavesDisturbCS"]->GetBufferPointer()),
  974.         mShaders["wavesDisturbCS"]->GetBufferSize()
  975.     };
  976.     wavesDisturbPSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  977.     ThrowIfFailed(md3dDevice->CreateComputePipelineState(&wavesDisturbPSO, IID_PPV_ARGS(&mPSOs["wavesDisturb"])));
  978.  
  979.     //
  980.     // PSO for updating waves
  981.     //
  982.     D3D12_COMPUTE_PIPELINE_STATE_DESC wavesUpdatePSO = {};
  983.     wavesUpdatePSO.pRootSignature = mWavesRootSignature.Get();
  984.     wavesUpdatePSO.CS =
  985.     {
  986.         reinterpret_cast<BYTE*>(mShaders["wavesUpdateCS"]->GetBufferPointer()),
  987.         mShaders["wavesUpdateCS"]->GetBufferSize()
  988.     };
  989.     wavesUpdatePSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  990.     ThrowIfFailed(md3dDevice->CreateComputePipelineState(&wavesUpdatePSO, IID_PPV_ARGS(&mPSOs["wavesUpdate"])));
  991. }
  992.  
  993. void WavesCSApp::BuildFrameResources()
  994. {
  995.     for(int i = 0; i < gNumFrameResources; ++i)
  996.     {
  997.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  998.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  999.     }
  1000. }
  1001.  
  1002. void WavesCSApp::BuildMaterials()
  1003. {
  1004.     auto grass = std::make_unique<Material>();
  1005.     grass->Name = "grass";
  1006.     grass->MatCBIndex = 0;
  1007.     grass->DiffuseSrvHeapIndex = 0;
  1008.     grass->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1009.     grass->FresnelR0 = XMFLOAT3(0.01f, 0.01f, 0.01f);
  1010.     grass->Roughness = 0.125f;
  1011.  
  1012.     // This is not a good water material definition, but we do not have all the rendering
  1013.     // tools we need (transparency, environment reflection), so we fake it for now.
  1014.     auto water = std::make_unique<Material>();
  1015.     water->Name = "water";
  1016.     water->MatCBIndex = 1;
  1017.     water->DiffuseSrvHeapIndex = 1;
  1018.     water->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.5f);
  1019.     water->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  1020.     water->Roughness = 0.0f;
  1021.  
  1022.     auto wirefence = std::make_unique<Material>();
  1023.     wirefence->Name = "wirefence";
  1024.     wirefence->MatCBIndex = 2;
  1025.     wirefence->DiffuseSrvHeapIndex = 2;
  1026.     wirefence->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1027.     wirefence->FresnelR0 = XMFLOAT3(0.02f, 0.02f, 0.02f);
  1028.     wirefence->Roughness = 0.25f;
  1029.  
  1030.     mMaterials["grass"] = std::move(grass);
  1031.     mMaterials["water"] = std::move(water);
  1032.     mMaterials["wirefence"] = std::move(wirefence);
  1033. }
  1034.  
  1035. void WavesCSApp::BuildRenderItems()
  1036. {
  1037.     auto wavesRitem = std::make_unique<RenderItem>();
  1038.     wavesRitem->World = MathHelper::Identity4x4();
  1039.     XMStoreFloat4x4(&wavesRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
  1040.     wavesRitem->DisplacementMapTexelSize.x = 1.0f / mWaves->ColumnCount();
  1041.     wavesRitem->DisplacementMapTexelSize.y = 1.0f / mWaves->RowCount();
  1042.     wavesRitem->GridSpatialStep = mWaves->SpatialStep();
  1043.     wavesRitem->ObjCBIndex = 0;
  1044.     wavesRitem->Mat = mMaterials["water"].get();
  1045.     wavesRitem->Geo = mGeometries["waterGeo"].get();
  1046.     wavesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1047.     wavesRitem->IndexCount = wavesRitem->Geo->DrawArgs["grid"].IndexCount;
  1048.     wavesRitem->StartIndexLocation = wavesRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  1049.     wavesRitem->BaseVertexLocation = wavesRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  1050.  
  1051.     mRitemLayer[(int)RenderLayer::GpuWaves].push_back(wavesRitem.get());
  1052.  
  1053.     auto gridRitem = std::make_unique<RenderItem>();
  1054.     gridRitem->World = MathHelper::Identity4x4();
  1055.     XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
  1056.     gridRitem->ObjCBIndex = 1;
  1057.     gridRitem->Mat = mMaterials["grass"].get();
  1058.     gridRitem->Geo = mGeometries["landGeo"].get();
  1059.     gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1060.     gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  1061.     gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  1062.     gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  1063.  
  1064.     mRitemLayer[(int)RenderLayer::Opaque].push_back(gridRitem.get());
  1065.  
  1066.     auto boxRitem = std::make_unique<RenderItem>();
  1067.     XMStoreFloat4x4(&boxRitem->World, XMMatrixTranslation(3.0f, 2.0f, -9.0f));
  1068.     boxRitem->ObjCBIndex = 2;
  1069.     boxRitem->Mat = mMaterials["wirefence"].get();
  1070.     boxRitem->Geo = mGeometries["boxGeo"].get();
  1071.     boxRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1072.     boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  1073.     boxRitem->StartIndexLocation = boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  1074.     boxRitem->BaseVertexLocation = boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;
  1075.  
  1076.     mRitemLayer[(int)RenderLayer::AlphaTested].push_back(boxRitem.get());
  1077.  
  1078.     mAllRitems.push_back(std::move(wavesRitem));
  1079.     mAllRitems.push_back(std::move(gridRitem));
  1080.     mAllRitems.push_back(std::move(boxRitem));
  1081. }
  1082.  
  1083. void WavesCSApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  1084. {
  1085.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  1086.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  1087.  
  1088.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  1089.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  1090.  
  1091.     // For each render item...
  1092.     for(size_t i = 0; i < ritems.size(); ++i)
  1093.     {
  1094.         auto ri = ritems[i];
  1095.  
  1096.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  1097.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  1098.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  1099.  
  1100.         CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  1101.         tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
  1102.  
  1103.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  1104.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  1105.  
  1106.         cmdList->SetGraphicsRootDescriptorTable(0, tex);
  1107.         cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
  1108.         cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
  1109.  
  1110.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  1111.     }
  1112. }
  1113.  
  1114. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> WavesCSApp::GetStaticSamplers()
  1115. {
  1116.     // Applications usually only need a handful of samplers.  So just define them all up front
  1117.     // and keep them available as part of the root signature.  
  1118.  
  1119.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  1120.         0, // shaderRegister
  1121.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1122.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1123.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1124.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1125.  
  1126.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  1127.         1, // shaderRegister
  1128.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1129.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1130.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1131.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1132.  
  1133.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  1134.         2, // shaderRegister
  1135.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1136.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1137.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1138.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1139.  
  1140.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  1141.         3, // shaderRegister
  1142.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1143.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1144.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1145.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1146.  
  1147.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  1148.         4, // shaderRegister
  1149.         D3D12_FILTER_ANISOTROPIC, // filter
  1150.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1151.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1152.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  1153.         0.0f,                             // mipLODBias
  1154.         8);                               // maxAnisotropy
  1155.  
  1156.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  1157.         5, // shaderRegister
  1158.         D3D12_FILTER_ANISOTROPIC, // filter
  1159.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1160.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1161.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  1162.         0.0f,                              // mipLODBias
  1163.         8);                                // maxAnisotropy
  1164.  
  1165.     return { 
  1166.         pointWrap, pointClamp,
  1167.         linearWrap, linearClamp, 
  1168.         anisotropicWrap, anisotropicClamp };
  1169. }
  1170.  
  1171. float WavesCSApp::GetHillsHeight(float x, float z)const
  1172. {
  1173.     return 0.3f*(z*sinf(0.1f*x) + x*cosf(0.1f*z));
  1174. }
  1175.  
  1176. XMFLOAT3 WavesCSApp::GetHillsNormal(float x, float z)const
  1177. {
  1178.     // n = (-df/dx, 1, -df/dz)
  1179.     XMFLOAT3 n(
  1180.         -0.03f*z*cosf(0.1f*x) - 0.3f*cosf(0.1f*z),
  1181.         1.0f,
  1182.         -0.3f*sinf(0.1f*x) + 0.03f*x*sinf(0.1f*z));
  1183.  
  1184.     XMVECTOR unitNormal = XMVector3Normalize(XMLoadFloat3(&n));
  1185.     XMStoreFloat3(&n, unitNormal);
  1186.  
  1187.     return n;
  1188. }
  1189.